﻿#include "StdAfx.h"
#include <shlwapi.h>

namespace DuiLib {

/////////////////////////////////////////////////////////////////////////////////////
//
//

void DUILIB_API DUI__Trace(LPCTSTR pstrFormat, ...)
{
#ifdef _DEBUG

    if (NULL != pstrFormat)
    {
        TCHAR szBuffer[300] = { 0 };
        va_list args;
        va_start(args, pstrFormat);
        ::wvnsprintf(szBuffer, LENGTHOF(szBuffer) - 2, pstrFormat, args);
        _tcsncat(szBuffer, _T("\n"), 1);
        va_end(args);
        ::OutputDebugString(szBuffer);
    }

#endif
}

LPCTSTR DUI__TraceMsg(UINT uMsg)
{
#define MSGDEF(x) if(uMsg==x) return _T(#x)
    MSGDEF(WM_SETCURSOR);
    MSGDEF(WM_NCHITTEST);
    MSGDEF(WM_NCPAINT);
    MSGDEF(WM_PAINT);
    MSGDEF(WM_ERASEBKGND);
    MSGDEF(WM_NCMOUSEMOVE);
    MSGDEF(WM_MOUSEMOVE);
    MSGDEF(WM_MOUSELEAVE);
    MSGDEF(WM_MOUSEHOVER);
    MSGDEF(WM_NOTIFY);
    MSGDEF(WM_COMMAND);
    MSGDEF(WM_MEASUREITEM);
    MSGDEF(WM_DRAWITEM);
    MSGDEF(WM_LBUTTONDOWN);
    MSGDEF(WM_LBUTTONUP);
    MSGDEF(WM_LBUTTONDBLCLK);
    MSGDEF(WM_RBUTTONDOWN);
    MSGDEF(WM_RBUTTONUP);
    MSGDEF(WM_RBUTTONDBLCLK);
    MSGDEF(WM_SETFOCUS);
    MSGDEF(WM_KILLFOCUS);
    MSGDEF(WM_MOVE);
    MSGDEF(WM_SIZE);
    MSGDEF(WM_SIZING);
    MSGDEF(WM_MOVING);
    MSGDEF(WM_GETMINMAXINFO);
    MSGDEF(WM_CAPTURECHANGED);
    MSGDEF(WM_WINDOWPOSCHANGED);
    MSGDEF(WM_WINDOWPOSCHANGING);
    MSGDEF(WM_NCCALCSIZE);
    MSGDEF(WM_NCCREATE);
    MSGDEF(WM_NCDESTROY);
    MSGDEF(WM_TIMER);
    MSGDEF(WM_KEYDOWN);
    MSGDEF(WM_KEYUP);
    MSGDEF(WM_CHAR);
    MSGDEF(WM_SYSKEYDOWN);
    MSGDEF(WM_SYSKEYUP);
    MSGDEF(WM_SYSCOMMAND);
    MSGDEF(WM_SYSCHAR);
    MSGDEF(WM_VSCROLL);
    MSGDEF(WM_HSCROLL);
    MSGDEF(WM_CHAR);
    MSGDEF(WM_SHOWWINDOW);
    MSGDEF(WM_PARENTNOTIFY);
    MSGDEF(WM_CREATE);
    MSGDEF(WM_NCACTIVATE);
    MSGDEF(WM_ACTIVATE);
    MSGDEF(WM_ACTIVATEAPP);
    MSGDEF(WM_CLOSE);
    MSGDEF(WM_DESTROY);
    MSGDEF(WM_GETICON);
    MSGDEF(WM_GETTEXT);
    MSGDEF(WM_GETTEXTLENGTH);
    static TCHAR szMsg[10];
    ::wnsprintf(szMsg, sizeof(szMsg)/sizeof(TCHAR), _T("0x%04X"), uMsg);
    return szMsg;
}

/////////////////////////////////////////////////////////////////////////////////////
//
//

//////////////////////////////////////////////////////////////////////////
//
DUI_BASE_BEGIN_MESSAGE_MAP(CNotifyPump)
DUI_END_MESSAGE_MAP()

static const DUI_MSGMAP_ENTRY *DuiFindMessageEntry(const DUI_MSGMAP_ENTRY *lpEntry, TNotifyUI &msg)
{
    CDuiString sMsgType = msg.sType;
    CDuiString sCtrlName = msg.pSender->GetName();
    const DUI_MSGMAP_ENTRY *pMsgTypeEntry = NULL;

    while (lpEntry->nSig != DuiSig_end)
    {
        if (lpEntry->sMsgType == sMsgType)
        {
            if (!lpEntry->sCtrlName.IsEmpty())
            {
                if (lpEntry->sCtrlName == sCtrlName)
                {
                    return lpEntry;
                }
            }
            else
            {
                pMsgTypeEntry = lpEntry;
            }
        }

        lpEntry++;
    }

    return pMsgTypeEntry;
}

bool CNotifyPump::AddVirtualWnd(CDuiString strName, CNotifyPump *pObject)
{
    if (m_VirtualWndMap.Find(strName) == NULL)
    {
        m_VirtualWndMap.Insert(strName.GetData(), (LPVOID)pObject);
        return true;
    }

    return false;
}

bool CNotifyPump::RemoveVirtualWnd(CDuiString strName)
{
    if (m_VirtualWndMap.Find(strName) != NULL)
    {
        m_VirtualWndMap.Remove(strName);
        return true;
    }

    return false;
}

bool CNotifyPump::LoopDispatch(TNotifyUI &msg)
{
    const DUI_MSGMAP_ENTRY *lpEntry = NULL;
    const DUI_MSGMAP *pMessageMap = NULL;

#ifndef UILIB_STATIC

    for (pMessageMap = GetMessageMap(); pMessageMap != NULL; pMessageMap = (*pMessageMap->pfnGetBaseMap)())
#else
    for (pMessageMap = GetMessageMap(); pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMap)
#endif
    {
#ifndef UILIB_STATIC
        ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
#else
        ASSERT(pMessageMap != pMessageMap->pBaseMap);
#endif

        if ((lpEntry = DuiFindMessageEntry(pMessageMap->lpEntries, msg)) != NULL)
        {
            goto LDispatch;
        }
    }

    return false;

LDispatch:
    bool bRet = false;

    if (NULL != lpEntry)
    {
        union DuiMessageMapFunctions mmf;
        mmf.pfn = lpEntry->pfn;
        int nSig;
        nSig = lpEntry->nSig;

        switch (nSig)
        {
        default:
            ASSERT(FALSE);
            break;

        case DuiSig_lwl:
            (this->*mmf.pfn_Notify_lwl)(msg.wParam, msg.lParam);
            bRet = true;
            break;

        case DuiSig_vn:
            (this->*mmf.pfn_Notify_vn)(msg);
            bRet = true;
            break;
        }
    }

    return bRet;
}

void CNotifyPump::NotifyPump(TNotifyUI &msg)
{
    ///遍历虚拟窗口
    if (!msg.sVirtualWnd.IsEmpty())
    {
        for (int i = 0; i < m_VirtualWndMap.GetSize(); i++)
        {
            if (LPCTSTR key = m_VirtualWndMap.GetAt(i))
            {
                if (_tcsicmp(key, msg.sVirtualWnd.GetData()) == 0)
                {
                    CNotifyPump *pObject = static_cast<CNotifyPump *>(m_VirtualWndMap.Find(key, false));

                    if (pObject && pObject->LoopDispatch(msg))
                    { return; }
                }
            }
        }
    }

    ///
    //遍历主窗口
    LoopDispatch(msg);
}

//////////////////////////////////////////////////////////////////////////
///
CWindowWnd::CWindowWnd()
    : m_hWnd(NULL)
    , m_hOwner(NULL)
    , m_OldWndProc(::DefWindowProc)
    , m_bSubclassed(false)
{
}

DUI_INLINE HWND CWindowWnd::GetHWND() const
{
    return m_hWnd;
}

DUI_INLINE UINT CWindowWnd::GetClassStyle() const
{
    return 0;
}

DUI_INLINE LPCTSTR CWindowWnd::GetSuperClassName() const
{
    return NULL;
}

DUI_INLINE CWindowWnd::operator HWND() const
{
    return m_hWnd;
}

DUI_INLINE HWND CWindowWnd::CreateDuiWindow(HWND hwndParent, LPCTSTR pstrWindowName, DWORD dwStyle,
                                            DWORD dwExStyle)
{
    return Create(hwndParent, pstrWindowName, dwStyle, dwExStyle, 0, 0, 0, 0, NULL);
}

DUI_INLINE HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle,
                                   const RECT rc, HMENU hMenu)
{
    return Create(hwndParent, pstrName, dwStyle, dwExStyle, rc.left, rc.top, rc.right - rc.left,
                  rc.bottom - rc.top, hMenu);
}

HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, int x, int y,
                        int cx, int cy, HMENU hMenu)
{
    if (GetSuperClassName() != NULL && !RegisterSuperclass()) { return NULL; }

    if (GetSuperClassName() == NULL && !RegisterWindowClass()) { return NULL; }

    m_sTitle = pstrName;
    m_sTitleOrig = m_sTitle;
    CPaintManagerUI::ProcessMultiLanguageTokens(m_sTitle);
    m_hWnd = ::CreateWindowEx(dwExStyle, GetWindowClassName(), m_sTitle.GetData(),
                              dwStyle, x, y, cx, cy, hwndParent, hMenu,
                              CPaintManagerUI::GetInstance(), this);
    ASSERT(m_hWnd != NULL);

    // 2017-02-09 完善多语言切换
    CPaintManagerUI::AddLanguageNotifier(m_hWnd);

    return m_hWnd;
}

HWND CWindowWnd::Subclass(HWND hWnd)
{
    ASSERT(::IsWindow(hWnd));
    ASSERT(m_hWnd == NULL);
    m_OldWndProc = SubclassWindow(hWnd, __WndProc);

    if (m_OldWndProc == NULL) { return NULL; }

    m_bSubclassed = true;
    m_hWnd = hWnd;
    ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(this));
    return m_hWnd;
}

void CWindowWnd::Unsubclass()
{
    ASSERT(::IsWindow(m_hWnd));

    if (!::IsWindow(m_hWnd)) { return; }

    if (!m_bSubclassed) { return; }

    SubclassWindow(m_hWnd, m_OldWndProc);
    m_OldWndProc = ::DefWindowProc;
    m_bSubclassed = false;
}

DUI_INLINE void CWindowWnd::ShowWindow(bool bShow /*= true*/, bool bTakeFocus /*= false*/)
{
    ASSERT(::IsWindow(m_hWnd));

    if (!::IsWindow(m_hWnd)) { return; }

    ::ShowWindow(m_hWnd, bShow ? (bTakeFocus ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE) : SW_HIDE);
}

UINT CWindowWnd::ShowModal()
{
    ASSERT(::IsWindow(m_hWnd));
    UINT nRet = 0;
    //HWND hWndParent = GetWindowOwner(m_hWnd);
    HWND hWndParent = GetOwner();
    ::ShowWindow(m_hWnd, SW_SHOWNORMAL);
    ::EnableWindow(hWndParent, FALSE);
    MSG msg = { 0 };

    while (::IsWindow(m_hWnd) && ::GetMessage(&msg, NULL, 0, 0))
    {
        if (msg.message == WM_CLOSE && msg.hwnd == m_hWnd)
        {
            nRet = msg.wParam;
            ::EnableWindow(hWndParent, TRUE);
            ::SetFocus(hWndParent);
        }

        if (!CPaintManagerUI::TranslateMessage(&msg))
        {
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
        }

        if (msg.message == WM_QUIT) { break; }
    }

    ::EnableWindow(hWndParent, TRUE);
    ::SetFocus(hWndParent);

    if (msg.message == WM_QUIT) { ::PostQuitMessage(msg.wParam); }

    return nRet;
}

void CWindowWnd::Close(UINT nRet, bool bSync)
{
    ASSERT(::IsWindow(m_hWnd));

    if (!::IsWindow(m_hWnd)) { return; }

    // 2018-08-15 zhuyadong 由于同步 WM_CLOSE 消息的存在，此句必须放在前面执行，否则可能导致崩溃
    // 2017-02-25 zhuyadong 完善多语言切换。
    CPaintManagerUI::DelLanguageNotifier(m_hWnd);

    if (bSync) { SendMessage(WM_CLOSE, (WPARAM)nRet, 0L); }
    else       { PostMessage(WM_CLOSE, (WPARAM)nRet, 0L); }
}

void CWindowWnd::CenterWindow()
{
    ASSERT(::IsWindow(m_hWnd));
    ASSERT((GetWindowStyle(m_hWnd) & WS_CHILD) == 0);
    RECT rcDlg = { 0 };
    ::GetWindowRect(m_hWnd, &rcDlg);
    RECT rcArea = { 0 };
    RECT rcCenter = { 0 };
    HWND hWnd = *this;
    HWND hWndParent = ::GetParent(m_hWnd);
    HWND hWndCenter = ::GetWindowOwner(m_hWnd);

    if (hWndCenter != NULL)
    { hWnd = hWndCenter; }

    // 处理多显示器模式下屏幕居中
    MONITORINFO oMonitor = {};
    oMonitor.cbSize = sizeof(oMonitor);
    ::GetMonitorInfo(::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &oMonitor);
    rcArea = oMonitor.rcWork;

    if (hWndCenter == NULL || IsIconic(hWndCenter))
    { rcCenter = rcArea; }
    else
    { ::GetWindowRect(hWndCenter, &rcCenter); }

    int DlgWidth = rcDlg.right - rcDlg.left;
    int DlgHeight = rcDlg.bottom - rcDlg.top;

    // Find dialog's upper left based on rcCenter
    int xLeft = (rcCenter.left + rcCenter.right) / 2 - DlgWidth / 2;
    int yTop = (rcCenter.top + rcCenter.bottom) / 2 - DlgHeight / 2;

    // The dialog is outside the screen, move it inside
    if (xLeft < rcArea.left) { xLeft = rcArea.left; }
    else if (xLeft + DlgWidth > rcArea.right) { xLeft = rcArea.right - DlgWidth; }

    if (yTop < rcArea.top) { yTop = rcArea.top; }
    else if (yTop + DlgHeight > rcArea.bottom) { yTop = rcArea.bottom - DlgHeight; }

    ::SetWindowPos(m_hWnd, NULL, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}

void CWindowWnd::MoveWindow(int x, int y)
{
    ASSERT(::IsWindow(m_hWnd));
    RECT rt = { 0, 0, 0, 0 };
    ::GetWindowRect(m_hWnd, &rt);
    ::MoveWindow(m_hWnd, x, y, rt.right - rt.left, rt.bottom - rt.top, FALSE);
}

void CWindowWnd::MoveWindow(int x, int y, int w, int h, BOOL bRepaint /*= FALSE*/)
{
    ASSERT(::IsWindow(m_hWnd));
    ::MoveWindow(m_hWnd, x, y, w, h, bRepaint);
}

void CWindowWnd::SetIcon(UINT nRes)
{
    // 防止某些 DPI 设置下图标模糊
    // HICON hIcon = (HICON)::LoadImage(CPaintManagerUI::GetInstance(), MAKEINTRESOURCE(nRes), IMAGE_ICON,
    //                                  ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
    HICON hIcon = (HICON)::LoadImage(CPaintManagerUI::GetInstance(), MAKEINTRESOURCE(nRes), IMAGE_ICON,
                                     (::GetSystemMetrics(SM_CXICON) + 15) & ~15,
                                     (::GetSystemMetrics(SM_CYICON) + 15) & ~15, LR_DEFAULTCOLOR);
    ASSERT(hIcon);
    ::SendMessage(m_hWnd, WM_SETICON, (WPARAM) TRUE, (LPARAM) hIcon);
    // 防止某些 DPI 设置下图标模糊
    // hIcon = (HICON)::LoadImage(CPaintManagerUI::GetInstance(), MAKEINTRESOURCE(nRes), IMAGE_ICON,
    //                            ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
    hIcon = (HICON)::LoadImage(CPaintManagerUI::GetInstance(), MAKEINTRESOURCE(nRes), IMAGE_ICON,
                               (::GetSystemMetrics(SM_CXSMICON) + 15) & ~15,
                               (::GetSystemMetrics(SM_CYSMICON) + 15) & ~15, LR_DEFAULTCOLOR);
    ASSERT(hIcon);
    ::SendMessage(m_hWnd, WM_SETICON, (WPARAM) FALSE, (LPARAM) hIcon);
}

void CWindowWnd::SetParent(HWND hParent)
{
    if (::IsWindow(m_hWnd)) { ::SetParent(m_hWnd, hParent); }
}

// GetParent的返回值比较复杂：
// 1. 对于overlapped类型的窗口，它返回0；
// 2. 对于WS_CHILD类型，它返回其父窗口；
// 3. 对于WS_POPUP类型，它返回其所有者窗口
//    如果想得到创建它时所传递进去的那个hwndParent参数，应该用GetWindowWord(GWW_HWNDPARENT)函数。？？？
HWND CWindowWnd::GetParent(HWND hWnd)
{
    if (::IsWindow(hWnd)) { return ::GetParent(hWnd); }
    else { return ::IsWindow(m_hWnd) ? ::GetParent(m_hWnd) : NULL; }
}

void CWindowWnd::SetOwner(HWND hOwner)
{
    m_hOwner = ::IsWindow(hOwner) ? hOwner : NULL;
}

HWND CWindowWnd::GetOwner()
{
    return m_hOwner ? m_hOwner : GetWindowOwner(m_hWnd);
}

bool CWindowWnd::RegisterWindowClass()
{
    WNDCLASS wc = { 0 };
    wc.style = GetClassStyle();
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hIcon = NULL;
    wc.lpfnWndProc = CWindowWnd::__WndProc;
    wc.hInstance = CPaintManagerUI::GetInstance();
    wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = NULL;
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = GetWindowClassName();
    ATOM ret = ::RegisterClass(&wc);
    ASSERT(ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS);
    return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
}

bool CWindowWnd::RegisterSuperclass()
{
    // Get the class information from an existing
    // window so we can subclass it later on...
    WNDCLASSEX wc = { 0 };
    wc.cbSize = sizeof(WNDCLASSEX);

    if (!::GetClassInfoEx(NULL, GetSuperClassName(), &wc))
    {
        if (!::GetClassInfoEx(CPaintManagerUI::GetInstance(), GetSuperClassName(), &wc))
        {
            ASSERT(!"Unable to locate window class");
            return NULL;
        }
    }

    m_OldWndProc = wc.lpfnWndProc;
    wc.lpfnWndProc = CWindowWnd::__ControlProc;
    wc.hInstance = CPaintManagerUI::GetInstance();
    wc.lpszClassName = GetWindowClassName();
    ATOM ret = ::RegisterClassEx(&wc);
    ASSERT(ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS);
    return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
}

LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CWindowWnd *pThis = NULL;

    if (uMsg == WM_NCCREATE)
    {
        LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
        pThis = static_cast<CWindowWnd *>(lpcs->lpCreateParams);
        pThis->m_hWnd = hWnd;
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
    }
    else
    {
        pThis = reinterpret_cast<CWindowWnd *>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));

        if (uMsg == WM_NCDESTROY && pThis != NULL)
        {
            LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
            ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);

            if (pThis->m_bSubclassed) { pThis->Unsubclass(); }

            pThis->m_hWnd = NULL;
            pThis->OnFinalMessage(hWnd);
            return lRes;
        }
    }

    if (pThis != NULL)
    {
        return pThis->HandleMessage(uMsg, wParam, lParam);
    }
    else
    {
        return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}

LRESULT CALLBACK CWindowWnd::__ControlProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CWindowWnd *pThis = NULL;

    if (uMsg == WM_NCCREATE)
    {
        LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
        pThis = static_cast<CWindowWnd *>(lpcs->lpCreateParams);
        ::SetProp(hWnd, _T("WndX"), (HANDLE) pThis);
        pThis->m_hWnd = hWnd;
    }
    else
    {
        pThis = reinterpret_cast<CWindowWnd *>(::GetProp(hWnd, _T("WndX")));

        if (uMsg == WM_NCDESTROY && pThis != NULL)
        {
            LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);

            if (pThis->m_bSubclassed) { pThis->Unsubclass(); }

            ::SetProp(hWnd, _T("WndX"), NULL);
            pThis->m_hWnd = NULL;
            pThis->OnFinalMessage(hWnd);
            return lRes;
        }
    }

    if (pThis != NULL)
    {
        return pThis->HandleMessage(uMsg, wParam, lParam);
    }
    else
    {
        return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}

DUI_INLINE void CWindowWnd::ReloadTitle(void)
{
    m_sTitle = m_sTitleOrig;
    CPaintManagerUI::ProcessMultiLanguageTokens(m_sTitle);
    ::SetWindowText(m_hWnd, m_sTitle.GetData());
}

DUI_INLINE LRESULT CWindowWnd::SendMessage(UINT uMsg, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
{
    ASSERT(::IsWindow(m_hWnd));
    return ::SendMessage(m_hWnd, uMsg, wParam, lParam);
}

DUI_INLINE LRESULT CWindowWnd::PostMessage(UINT uMsg, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
{
    ASSERT(::IsWindow(m_hWnd));
    return ::PostMessage(m_hWnd, uMsg, wParam, lParam);
}

void CWindowWnd::ResizeClient(int cx /*= -1*/, int cy /*= -1*/)
{
    ASSERT(::IsWindow(m_hWnd));
    RECT rc = { 0 };

    if (!::GetClientRect(m_hWnd, &rc)) { return; }

    if (cx != -1) { rc.right = cx; }

    if (cy != -1) { rc.bottom = cy; }

    if (!::AdjustWindowRectEx(&rc, GetWindowStyle(m_hWnd),
                              (!(GetWindowStyle(m_hWnd) & WS_CHILD) && (::GetMenu(m_hWnd) != NULL)),
                              GetWindowExStyle(m_hWnd)))
    { return; }

    ::SetWindowPos(m_hWnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
                   SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
}

DUI_INLINE LRESULT CWindowWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    return ::CallWindowProc(m_OldWndProc, m_hWnd, uMsg, wParam, lParam);
}

DUI_INLINE void CWindowWnd::OnFinalMessage(HWND /*hWnd*/)
{
}

} // namespace DuiLib
